package com.wyapples.kittcar;

import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Locale;
import java.util.concurrent.Delayed;

import android.R.integer;
import android.R.string;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.speech.RecognizerIntent;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckedTextView;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;

public class CarActivity extends Activity implements
		TextToSpeech.OnInitListener, Runnable {
	private static final String TAG = "Kitt Car";
	private static final int VOICE_RECOGNITION_REQUEST_CODE = 0x23;
	private static final String ACTION_USB_PERMISSION = "com.wyapples.kittcar.USB_PERMISSION";
	private boolean oneActionFinished;

	private static final int KITT = 1;
	private static final int ME = 2;
	private String iSayString;
	private String kittSayString;
	private LinearLayout talklLinearLayout;
	private ScrollView scrollView;
	private LayoutInflater liInflater;
	private Handler mHandler;

	UsbAccessory mAccessory;
	ParcelFileDescriptor mFileDescriptor;
	FileInputStream mInputStream;
	FileOutputStream mOutputStream;

	private UsbManager mUsbManager;
	private PendingIntent mPermissionIntent;
	private boolean mPermissionRequestPending;

	private TextToSpeech mSpeech;
	private Kitt kitt;

	private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {

		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
			if (ACTION_USB_PERMISSION.equals(action)) {
				synchronized (this) {
					UsbAccessory accessory = (UsbAccessory) intent
							.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);

					if (intent.getBooleanExtra(
							UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
						if (accessory != null) {
							// call method to set up accessory communication
							openAccessory(accessory);
						}
					} else {
						Log.d(TAG, "permission denied for accessory "
								+ accessory);
					}
					mPermissionRequestPending = false;
				}
			} else if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
				UsbAccessory accessory = (UsbAccessory) intent
						.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
				if (accessory != null && accessory.equals(mAccessory)) {
					closeAccessory();
					Toast.makeText(getApplicationContext(), "fuck",
							Toast.LENGTH_SHORT).show();
				}
			}

		}
	};

	private Runnable scrollToBottom = new Runnable() {

		@Override
		public void run() {
			scrollView.scrollTo(0, talklLinearLayout.getMeasuredHeight()
					- scrollView.getHeight());
		}
	};

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		liInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		talklLinearLayout = (LinearLayout) findViewById(R.id.talk_list);
		scrollView = (ScrollView) findViewById(R.id.ScrollView1);
		mHandler = new Handler();

		mUsbManager = (UsbManager) getSystemService(Context.USB_SERVICE);
		mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(
				ACTION_USB_PERMISSION), 0);
		IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
		filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
		registerReceiver(mUsbReceiver, filter);

		kitt = new Kitt();
		mSpeech = new TextToSpeech(this, this);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// TODO Auto-generated method stub
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.main_menu, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// TODO Auto-generated method stub
		switch (item.getItemId()) {
		case R.id.speak:
			startVoiceRecognitionActivity();
			return true;
		case R.id.about:
			return true;
		default:
			return super.onOptionsItemSelected(item);
		}

	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		// TODO Auto-generated method stub
		if (requestCode == VOICE_RECOGNITION_REQUEST_CODE
				&& resultCode == RESULT_OK) {
			ArrayList<String> matches = data
					.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);

			iSayString = matches.get(0);
			appendTalkItem(ME);
			kitt.beTold(matches);
			kittSayString = kitt.getWhatToSay();
			appendTalkItem(KITT);
			mSpeech.speak(kittSayString, TextToSpeech.QUEUE_FLUSH, null);

			if (kitt.readyToGo) {
				ArrayList<Command> commands = kitt.getCommands();
				for (Command command : commands) {
					sendCommand((byte) command.getCommand(),
							command.getParameter());
					 while (oneActionFinished == false) {
					 // do nothing
					 }

					kitt.readyToGo = false;
				}

				kitt.cleanUp();
			}
		}

		super.onActivityResult(requestCode, resultCode, data);
	}

	@Override
	public void onResume() {
		super.onResume();

		Intent intent = getIntent();
		if (mInputStream != null && mOutputStream != null) {
			return;
		}

		UsbAccessory[] accessories = mUsbManager.getAccessoryList();
		UsbAccessory accessory = (accessories == null ? null : accessories[0]);
		if (accessory != null) {
			if (mUsbManager.hasPermission(accessory)) {
				openAccessory(accessory);
			} else {
				synchronized (mUsbReceiver) {
					if (!mPermissionRequestPending) {
						mUsbManager.requestPermission(accessory,
								mPermissionIntent);
						mPermissionRequestPending = true;
					}
				}
			}
		} else {
			Log.d(TAG, "mAccessory is null");
		}
	}

	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		if (mSpeech != null) {
			mSpeech.stop();
			mSpeech.shutdown();
		}

		unregisterReceiver(mUsbReceiver);
		super.onDestroy();
	}

	@Override
	public void onInit(int status) {
		// TODO Auto-generated method stub
		mSpeech.setLanguage(Locale.US);
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		int ret = 0;
		byte[] buffer = new byte[16384];

		while (ret >= 0) {
			try {
				ret = mInputStream.read(buffer);
			} catch (IOException e) {
				break;
			}

			if (buffer[0] == 1) {
				oneActionFinished = true;
			} else
				oneActionFinished = false;

		}

	}

	private void startVoiceRecognitionActivity() {
		Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);

		// Specify the calling package to identify your application
		intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE, getClass()
				.getPackage().getName());

		// Display an hint to the user about what he should say.
		intent.putExtra(RecognizerIntent.EXTRA_PROMPT,
				"Speech recognition demo");

		// Given an hint to the recognizer about what the user is going to say
		intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
				RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);

		// Specify how many results you want to receive. The results will be
		// sorted
		// where the first result is the one with higher confidence.
		intent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 5);

		startActivityForResult(intent, VOICE_RECOGNITION_REQUEST_CODE);
	}

	private void openAccessory(UsbAccessory accessory) {
		Log.d(TAG, "openAccessory: " + accessory);
		mFileDescriptor = mUsbManager.openAccessory(accessory);
		if (mFileDescriptor != null) {
			mAccessory = accessory;
			FileDescriptor fd = mFileDescriptor.getFileDescriptor();
			mInputStream = new FileInputStream(fd);
			mOutputStream = new FileOutputStream(fd);
			Thread thread = new Thread(null, this, "AccessoryThread");
			thread.start();
		}
	}

	private void closeAccessory() {
		try {
			if (mFileDescriptor != null) {
				mFileDescriptor.close();
			}
		} catch (IOException e) {
		} finally {
			mFileDescriptor = null;
			mAccessory = null;
		}
	}

	public void sendCommand(byte command, int value) {
		byte[] buffer = new byte[2];
		if (value > 255)
			value = 255;

		buffer[0] = command;
		buffer[1] = (byte) value;
		if (mOutputStream != null) {
			try {
				mOutputStream.write(buffer);
			} catch (IOException e) {
				Log.e(TAG, "write failed", e);
			}
		}
	}

	private void appendTalkItem(int talktype) {
		View talkItem;
		TextView mTextView;

		switch (talktype) {
		case KITT:
			talkItem = liInflater.inflate(R.layout.talk_kitt_item, null);
			mTextView = (TextView) talkItem.findViewById(R.id.kitt_say);
			mTextView.setText(kittSayString);
			talklLinearLayout.addView(talkItem);
			break;
		case ME:
			talkItem = liInflater.inflate(R.layout.talk_me_item, null);
			mTextView = (TextView) talkItem.findViewById(R.id.me_say);
			mTextView.setText(iSayString);
			talklLinearLayout.addView(talkItem);
			break;
		default:
			break;
		}

		mHandler.post(scrollToBottom);

	}
}